#include "stdio.h"
#include "riscv.h"
#include "mmulayout.h"
#include "type.h"
#include "utils.h"

#include "plic.h"

#include "dbg.h"

#define WRITE_B(v, addr) (*(volatile uint8_t*)(addr)) = (v)
#define WRITE_W(v, addr) (*(volatile uint16_t*)(addr)) = (v)
#define WRITE_D(v, addr) (*(volatile uint32_t*)(addr)) = (v)
#define WRITE_Q(v, addr) (*(volatile uint64_t*)(addr)) = (v)

void
plicinit(void) {
    __DEBUG_FUNC_START;
    WRITE_D(1, PLIC_V + DISK_IRQ * sizeof(uint32_t));
    WRITE_D(1, PLIC_V + UART_IRQ * sizeof(uint32_t));
    __DEBUG_FUNC_END;
}

void
plicinithart(void) {
    __DEBUG_FUNC_START;
    uint32_t hart = r_tp();
#ifdef QEMU
    // set uart's enable bit for this hart's S-mode.
    *(uint32_t*)PLIC_SENABLE(hart) = (1 << UART_IRQ) | (1 << DISK_IRQ);
    // set this hart's S-mode priority threshold to 0
    *(uint32_t*)PLIC_SPRIORITY(hart) = 0;
#else
    uint32_t* hart_m_enable = (uint32_t*)PLIC_MENABLE(hart);
    *(hart_m_enable) = readd(hart_m_enable) | (1 << DISK_IRQ);
    uint32_t* hart0_m_int_enable_hi = hart_m_enable + 1;
    *(hart0_m_int_enable_hi) = readd(hart0_m_int_enable_hi) | (1 << (UART_IRQ % 32));
#endif
    __DEBUG_FUNC_END;
}

int
plic_claim(void) {
    int hart = r_tp();
    int irq;
#ifdef QEMU
    irq = *(uint32_t*)PLIC_SCLAIM(hart);
#else
    irq = *(uint32_t*)PLIC_MCLAIM(hart);
#endif

#ifdef DEBUG
    // printf("plic_claim, irq = %d\n", irq);
#endif
    return irq;
}

void
plic_complete(int irq) {
    int hart = r_tp();
#ifdef QEMU
    *(uint32_t*)PLIC_MCLAIM(hart) = irq;
#else
    *(uint32_t*)PLIC_SCLAIM(hart) = irq;
#endif

#ifdef DEBUG
    // printf("plic_complete, irq = %d\n", irq);
#endif
}